package l1j.opqlo.NewSystem.Play18La;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Set;
import java.util.TimerTask;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledFuture;
import java.util.logging.Level;
import java.util.logging.Logger;

import l1j.opqlo.NewSystem.各項記錄輸出;
import l1j.opqlo.Server.L1World.L1World;
import l1j.server.DatabaseFactory;
import l1j.server.Thread.PcOtherThreadPool;
import l1j.server.server.datatables.ItemTable;
import l1j.server.server.model.L1Object;
import l1j.server.server.model.Instance.L1ItemInstance;
import l1j.server.server.model.Instance.L1MerchantInstance;
import l1j.server.server.model.Instance.L1PcInstance;
import l1j.server.server.serverpackets.S_NpcChatPacket;
import l1j.server.server.serverpackets.S_SystemMessage;
import l1j.server.server.utils.Random;
import l1j.server.server.utils.SQLUtil;

public class Play18La {
	private static final Logger _log = Logger.getLogger(Play18La.class.getName());

	private HashMap<Integer , ConcurrentHashMap<Integer , Play18LaTemp>> _map = new HashMap<Integer , ConcurrentHashMap<Integer , Play18LaTemp>>();
	private int[]_numbers = {0 , 0 };//中獎號碼
	private HashMap<Integer , Double>_oddsTable = new HashMap<Integer , Double>();
	private HashMap<Integer , Integer>_objMap = new HashMap<Integer , Integer>();
	private HashMap<String , Integer>_accountNameMap = new HashMap<String , Integer>();
	private StringBuilder _msgLog = new StringBuilder();
	ConcurrentHashMap<Integer , Integer>_betMap = new ConcurrentHashMap<Integer , Integer>();
	private static Play18La _instance;
	private Thread18La _game;
	private boolean _isStart;
	private int _hasBet;
	private L1MerchantInstance _npc;
	private int _amount=0;
	private boolean _serverReStart;


	public static Play18La get(){
		if(_instance == null){
			_instance = new Play18La();
			_instance.start();
		}
		return _instance;
	}

	/**骰寶系統初始化*/
	private void start(){
		for(int i=1; i<=9; i++){
			_oddsTable.put(i, 3.5D);
		}
		_oddsTable.put(10, 1.5D);
		_oddsTable.put(11, 1.5D);
		for(int i=0; i<=11; i++){
			_map.put(i, new ConcurrentHashMap<Integer , Play18LaTemp>());
		}
		for (final L1Object obj : L1World.getInstance().getObject()) {
			if (obj instanceof L1MerchantInstance) {
				if(((L1MerchantInstance) obj).getNpcId() == 710092){
					_npc = (L1MerchantInstance) obj;
					break;
				}
			}
		}
		if(_npc ==null){
			System.out.println("骰寶NPC設置異常[在世界中找不到NPC編號 710092]。");
			return;
		}
		_game = new Thread18La();
		_game.startGame();
	}

	/**玩家下注骰寶*/
	public boolean BetMoney(final L1PcInstance pc , final int type){
		if(_isStart || _serverReStart){
			pc.sendPackets(new S_SystemMessage("賭局尚未開始，無法下注。"));
			return false;
		}
		final int betCount = pc.BET_RATE;
		final ConcurrentHashMap<Integer , Play18LaTemp> list = _map.get(type);
		final int objid = pc.getId();
		Play18LaTemp temp = list.get(objid);
		final Integer totalBet = _betMap.get(objid);
		if(totalBet == null){
			_betMap.put(objid, betCount);
		}else{
			final int i = totalBet + betCount;
			if(i >5000){
				pc.sendPackets(new S_SystemMessage("總下注金額不可超過5000。"));
				return false;
			}
			_betMap.put(objid , i );
		}
		if(temp ==null){
			temp = new Play18LaTemp();
			list.put(objid, temp);
			temp.setAccountName(pc.getAccountName());
			temp.setBet(betCount);
			String typeS = (type<=9? String.valueOf(type) : (type==10? "大" : "小"));
			_msgLog.append("\r\nIP:").append(pc.getNetConnection().getIp()).append("	玩家:").append(pc.getName()).append("(").append(objid).append(")	下注:")
			.append(typeS).append(" 金額:").append(betCount);
			_hasBet++;//有人下注
			pc.sendPackets(new S_SystemMessage("下注【"+typeS+"】 金額:"+betCount));
		}else{
			final int count = temp.getBet();
			final int allBet = count+betCount;
			temp.setBet(allBet);
			String typeS = (type<=9? String.valueOf(type) : (type==10? "大" : "小"));
			_msgLog.append("\r\nIP:").append(pc.getNetConnection().getIp()).append("	玩家:").append(pc.getName()).append("(").append(objid).append(")	加注:")
			.append(typeS).append(" 金額:").append(betCount).append(" / ").append(count);
			pc.sendPackets(new S_SystemMessage("增加下注【"+typeS+"】 總額:"+allBet));
		}
		_amount+= betCount;
		return true;
	}

	/**結束骰寶遊戲，還回各自押注至倉庫(用於伺服器重起)*/
	public void StopGame(){
		if(_serverReStart == false){
		_serverReStart = true;
		if( _game !=null){
			_game.stopGame();
			_game = null;
		}
		setItemToWereHouse();
		_npc.wideBroadcastPacket(new S_NpcChatPacket(_npc, "伺服器準備維修，賭局停止。", 2));
		}
	}
	private void setItemToWereHouse(){
		if(_hasBet <=0){
			return;
		}
		final Collection<ConcurrentHashMap<Integer , Play18LaTemp>>list =_map.values();
		_msgLog.append("\r\n--------(維修重啟發回下注)--------");
		if(list !=null && !list.isEmpty()){
			final S_SystemMessage packets = new S_SystemMessage("伺服器準備維修，您的下注金額已經補發到倉庫中。");
			final Iterator<ConcurrentHashMap<Integer, Play18LaTemp>>iterator = list.iterator();
			while(iterator.hasNext()){
				final ConcurrentHashMap<Integer, Play18LaTemp> map = iterator.next();
				final Set<Integer> mapSet = map.keySet();
				final Iterator<Integer> mapIte = mapSet.iterator();
				while(mapIte.hasNext()){
					final int key = mapIte.next();
					final Play18LaTemp temp = map.get(key);
					final L1ItemInstance item = ItemTable.getInstance().createItem(90308);
					final int count = temp.getBet();
					item.setCount(count);
					insertItem(item , temp.getAccountName());
					_msgLog.append("\r\n帳號: ").append(key).append("	下注中獎:").append(item.getLogName()).append(" 流水號:").append(item.getId());
					final L1Object obj = L1World.getInstance().findObject(key);
					if(obj !=null && obj instanceof L1PcInstance){
						final L1PcInstance pc = (L1PcInstance)obj;
						pc.sendPackets(packets);
					}
				}
			}
		}
		_msgLog.append("\r\n");
		各項記錄輸出.LogSave(35, _msgLog.toString());
		_msgLog.delete(0, _msgLog.length());
	}


	//[ 0=豹子  7=大  8=小 ]
	class Thread18La  extends TimerTask {
		private ScheduledFuture<?> _timer;
		private StringBuilder _msg;
		public void startGame(){
			this._timer = PcOtherThreadPool.get().scheduleAtFixedRate(this,10000, 10000);
		}
		public void stopGame(){
			PcOtherThreadPool.get().cancel(_timer, false);
			count=-1;
		}
		private int count ;
		@Override
		public void run() {

			if(count == -1 || _serverReStart){
				return;
			}else if(count ==0){
				_npc.wideBroadcastPacket(new S_NpcChatPacket(_npc, "下注[開始]，搖骰中。", 2));
				_numbers[0] = Random.nextInt(10);
				_numbers[1] = Random.nextInt(10);
				count++;
				String total ;
				if(_numbers[0] == _numbers[1]){
					total = "【雙骰】通殺!";
				}else{
					total = (_numbers[0] + _numbers[1]>= 10?  " [大]" : " [小]");
				}
				_msgLog.append("本次獎號為: ").append(_numbers[0]).append(" 、 ").append(_numbers[1])
				.append(total)
				.append(" 搖獎時間:(").append(new Timestamp(System.currentTimeMillis())).append(")");
				_isStart = false;
			}else if(count == 5){
				_npc.wideBroadcastPacket(new S_NpcChatPacket(_npc, "下注將於10秒後結束。", 2));
				count++;
			}else if(count ==6){
				count++;
				try{
					_isStart = true;
					String total ;
					if(_numbers[0] == _numbers[1]){
						total = "【雙骰】通殺!";
					}else{
						total = (_numbers[0] + _numbers[1]>= 10?  _numbers[0] + _numbers[1]+"點"+"[大]" : _numbers[0] + _numbers[1]+"點"+"[小]");
					}
					_npc.wideBroadcastPacket(new S_NpcChatPacket(_npc, "下注[停止]，打開骰盅。", 2));
					_msg = new StringBuilder().append("本次開出: ");
					_msg.append("[").append(_numbers[0]).append("]、[").append(_numbers[1]).append("] ").append(total);
					if(_numbers[0] == _numbers[1]){//豹子 除押注豹子外其他通殺
						//						final ConcurrentHashMap<Integer , Play18LaTemp> list =_map.get(0);
						//						if(list !=null && !list.isEmpty()){
						//							final Set<Integer>set = list.keySet();
						//							final Iterator<Integer> iterator = set.iterator();
						//							while(iterator.hasNext()){
						//								final int objid = iterator.next();
						//								final L1Object obj = L1World.getInstance().findObject(objid);
						//								final Play18LaTemp temp = _map.get(0).get(objid);
						//								final int bonusCount = (int) (temp.getBet() * 24D);
						//
						//								if(obj !=null && obj instanceof L1PcInstance){
						//									Integer count = _objMap.get(objid);
						//									if(count == null){
						//										_objMap.put(objid, bonusCount);
						//									}else{
						//										_objMap.put(objid, bonusCount+count);
						//									}
						//								}else{
						//									Integer count = _accountNameMap.get(objid);
						//									if(count == null){
						//										_accountNameMap.put(temp.getAccountName(), bonusCount);
						//									}else{
						//										_accountNameMap.put(temp.getAccountName(), bonusCount+count);
						//									}
						//								}
						//
						//							}
						//						}
					}else{
						for(final int number : _numbers){
							final ConcurrentHashMap<Integer , Play18LaTemp> map = _map.get(number);
							if(map !=null && !map.isEmpty()){
								final Set<Integer>set = map.keySet();
								final Iterator<Integer> iterator= set.iterator();
								while(iterator.hasNext()){
									final int objid = iterator.next();
									final Play18LaTemp temp = map.get(objid);
									final int bonusCount = (int) (temp.getBet() * _oddsTable.get(number));
									final L1Object obj = L1World.getInstance().findObject(objid);
									if(obj !=null && obj instanceof L1PcInstance){
										Integer count = _objMap.get(objid);
										if(count == null){
											_objMap.put(objid, bonusCount);
										}else{
											_objMap.put(objid, bonusCount+count);
										}
									}else{
										Integer count = _accountNameMap.get(objid);
										if(count == null){
											_accountNameMap.put(temp.getAccountName(), bonusCount);
										}else{
											_accountNameMap.put(temp.getAccountName(), bonusCount+count);
										}
									}
								}
							}
						}
						final int allPoint = _numbers[0] + _numbers[1];
						final int type = (allPoint >= 10 &&  allPoint<=18 ? 10 : 11);
						final ConcurrentHashMap<Integer , Play18LaTemp> map = _map.get(type);
						if(map !=null && !map.isEmpty()){
							final Set<Integer>set = map.keySet();
							final Iterator<Integer> iterator= set.iterator();
							while(iterator.hasNext()){
								final int objid = iterator.next();
								final Play18LaTemp temp = map.get(objid);
								final int bonusCount = (int) (temp.getBet() * _oddsTable.get(type));
								final L1Object obj = L1World.getInstance().findObject(objid);
								if(obj !=null && obj instanceof L1PcInstance){
									Integer count = _objMap.get(objid);
									if(count == null){
										_objMap.put(objid, bonusCount);
									}else{
										_objMap.put(objid, bonusCount+count);
									}
								}else{
									Integer count = _accountNameMap.get(objid);
									if(count == null){
										_accountNameMap.put(temp.getAccountName(), bonusCount);
									}else{
										_accountNameMap.put(temp.getAccountName(), bonusCount+count);
									}
								}
							}//wile end
						}
					}
					_npc.wideBroadcastPacket(new S_NpcChatPacket(_npc, _msg.toString(), 2));
					_msg.delete(0, _msg.length());
					_msg.append("中獎注數 : ").append((_accountNameMap.size() + _objMap.size())).append(_hasBet>0? " / "+_hasBet : "").append("注。");
					_npc.wideBroadcastPacket(new S_NpcChatPacket(_npc, _msg.toString(), 2));
					_msg.delete(0, _msg.length());
					if(_hasBet >0){
						_msgLog.append("\r\n中獎注數: ").append((_accountNameMap.size() + _objMap.size())).append("注。\r\n--------(中獎清單)--------");
					}
					payMoneyByObjId();
					payMoneyByAccountName();
					for(final ConcurrentHashMap<Integer , Play18LaTemp> ccmap : _map.values()){
						ccmap.clear();
					}
					count =0;
				}catch(Exception e){
					PcOtherThreadPool.get().cancel(_timer, false);
					Thread18La t18La = new Thread18La();
					this._timer = PcOtherThreadPool.get().scheduleAtFixedRate( t18La , 60000 , 10000);
					_log.log(Level.SEVERE , e.getLocalizedMessage() , e);
					setItemToWereHouse();
				}
				if(_hasBet >0){
					_msgLog.append("\r\n盈餘:").append(_amount);
					各項記錄輸出.LogSave(35, _msgLog.toString());
				}
				_msgLog.delete(0, _msgLog.length());
				_hasBet = 0;
				_betMap.clear();
			}else{
				count++;
			}
		}
	}
	private void payMoneyByObjId(){
		if(_objMap.isEmpty()){
			return;
		}
		Set<Integer>set = _objMap.keySet();
		Iterator<Integer> iterator = set.iterator();
		while(iterator.hasNext()){
			final int key = iterator.next();
			L1Object obj = L1World.getInstance().findObject(key);
			if(obj !=null && obj instanceof L1PcInstance){
				final L1ItemInstance item =  ItemTable.getInstance().createItem(90308);
				final int count = _objMap.get(key);
				item.setCount(count);
				_amount-=count;
				final L1PcInstance winner = (L1PcInstance)obj;
				winner.getInventory().storeItem(item);
				winner.sendPackets(new S_SystemMessage("恭喜!下注中獎，獲得:"+item.getLogName()+"。"));
				_msgLog.append("\r\n").append(winner.getName()).append(" (").append(key).append(")	下注中獎:").append(item.getLogName());
			}else{
				_accountNameMap.put(loadChaAccountName(key) , _objMap.get(key));
			}
		}
		_objMap.clear();
	}
	private void payMoneyByAccountName(){
		if(_accountNameMap.isEmpty()){
			return;
		}
		if(_hasBet >0){
			_msgLog.append("--------(發放至倉庫)--------");
		}
		Set<String>set = _accountNameMap.keySet();
		Iterator<String> iterator = set.iterator();
		while(iterator.hasNext()){
			final String key = iterator.next();
			final L1ItemInstance item =  ItemTable.getInstance().createItem(90308);
			final int count = _accountNameMap.get(key);
			_amount-=count;
			item.setCount(count);
			insertItem(item , key);
			_msgLog.append("\r\n帳號: ").append(key).append("	下注中獎:").append(item.getLogName()).append(" 流水號:").append(item.getId());
		}
		_accountNameMap.clear();
	}

	private void insertItem(final L1ItemInstance item, String accountname) {
		Connection con = null;
		PreparedStatement pstm = null;
		try {
			con = DatabaseFactory.get().getConnection();
			pstm = con
					.prepareStatement("INSERT INTO character_warehouse SET id = ?, account_name = ?, item_id = ?, item_name = ?, count = ?, is_equipped=0, enchantlvl = ?, is_id = ?, durability = ?, charge_count = ?, remaining_time = ?, last_used = ?, bless = ?, attr_enchant_kind = ?, attr_enchant_level = ?, firemr = ?, watermr = ?, earthmr = ?, windmr = ?, addsp = ?, addhp = ?, addmp = ?, hpr = ?, mpr = ?, SkillType = ?, level=?, 屬性增傷=?, 六屬性加成=?, 破甲=?, 抵擋=?, 額外攻擊=?, 攻擊成功=?, 經驗=?, 爆擊=?, 大怪=?, 小怪=?, 魔防=?,種族增傷=? ,暈眩 =?, 石化 =?, 睡眠 =?, 凍結 =?, 支撐 =?, 暗黑 =?, 暈眩抗性=?, 石化抗性=? , 睡眠抗性=? , 凍結抗性=? , 支撐抗性=? , 暗黑抗性=? , 掉寶率=?");
			pstm.setInt(1, item.getId());
			pstm.setString(2, accountname);
			pstm.setInt(3, item.getItemId());
			pstm.setString(4, item.getName());
			pstm.setLong(5, item.getCount());
			pstm.setInt(6, item.getEnchantLevel());
			pstm.setInt(7, item.isIdentified() ? 1 : 0);
			pstm.setInt(8, item.get_durability());
			pstm.setInt(9, item.getChargeCount());
			pstm.setInt(10, item.getRemainingTime());
			pstm.setTimestamp(11, item.getLastUsed());
			pstm.setInt(12, item.getBless());
			pstm.setInt(13, item.getAttrEnchantKind());
			pstm.setInt(14, item.getAttrEnchantLevel());
			// TODO 飾品強化卷軸修正無法存取人物物品資料
			pstm.setInt(15, item.getFireMr());
			pstm.setInt(16, item.getWaterMr());
			pstm.setInt(17, item.getEarthMr());
			pstm.setInt(18, item.getWindMr());
			pstm.setInt(19, item.getaddSp());
			pstm.setInt(20, item.getaddHp());
			pstm.setInt(21, item.getaddMp());
			pstm.setInt(22, item.getHpr());
			pstm.setInt(23, item.getMpr());
			// TODO 飾品強化卷軸修正無法存取人物物品資料
			// TODO 魔法武器卷軸by missu0524
			pstm.setInt(24, item.getSkillType());
			// TODO 魔法武器卷軸by missu0524
			// opqlo 道具升級系統START
			pstm.setInt(25, item.getLevel());
			// opqlo 道具升級系統END
			pstm.setString(26, item.getLvStatus().saveItemSpecialDmg(0));
			pstm.setString(27, item.getLvStatus().saveItemSpecialDmg(1));
			pstm.setInt(28, item.getExtraDmg());
			pstm.setInt(29, item.getExtraDef());
			pstm.setInt(30, item.getModDmg());
			pstm.setInt(31, item.getModHit());
			pstm.setDouble(32, item.getExpUp());
			pstm.setDouble(33, item.getDoubleDmg());
			pstm.setDouble(34, item.getBigDmg());
			pstm.setDouble(35, item.getSmallDmg());
			pstm.setInt(36, item.getaddMr());
			pstm.setString(37, item.getLvStatus().saveItemSpecialDmg(2));
			pstm.setInt(38, item.getStunDice());
			pstm.setInt(39, item.getStoneDice());
			pstm.setInt(40, item.getSleepDice());
			pstm.setInt(41, item.getFreezeDice());
			pstm.setInt(42, item.getSustainDice());
			pstm.setInt(43, item.getBlindDice());
			pstm.setInt(44, item.getStunMr());
			pstm.setInt(45, item.getStoneMr());
			pstm.setInt(46, item.getSleepMr());
			pstm.setInt(47, item.getFreezeMr());
			pstm.setInt(48, item.getSustainMr());
			pstm.setInt(49, item.getBlindMr());
			pstm.setDouble(50, item.getDroprate());
			pstm.execute();
		} catch (final Exception e) {
			_log.log(Level.SEVERE, e.getLocalizedMessage(), e);
		} finally {
			SQLUtil.close(pstm);
			SQLUtil.close(con);
		}
	}
	public String loadChaAccountName(final int objid) {
		Connection con = null;
		PreparedStatement pstm = null;
		ResultSet rs = null;
		try {
			con = DatabaseFactory.get().getConnection();
			pstm = con.prepareStatement("SELECT account_name FROM characters WHERE objid=?");
			pstm.setInt(1, objid);
			rs = pstm.executeQuery();
			if (rs.next()) {
				return rs.getString(1);
			}
		} catch (SQLException e) {
			_log.log(Level.SEVERE, e.getLocalizedMessage(), e);
			return null;
		} finally {
			SQLUtil.close(rs , pstm , con);
		}
		return null;
	}
	class Play18LaTemp{

		private String _accountName;
		private int _bet;

		public String getAccountName(){
			return _accountName;
		}
		public void setAccountName(final String s){
			_accountName = s;
		}
		public int getBet(){
			return _bet;
		}
		public void setBet(final int i){
			_bet = i;
		}
	}
}
